home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1998 July / EnigmA AMIGA RUN 29 (1998)(G.R. Edizioni)(IT)[!][issue 1998-07 & 08].iso / earcd / haage&partner / stormc / radiodiallib / radiodiallib.c < prev    next >
C/C++ Source or Header  |  1998-04-22  |  19KB  |  599 lines

  1. /*
  2.         radiodiallib.c
  3.  
  4.         Amiga shard library to serve as an example
  5.         how to develope external gadgets for StormWIZARD.
  6.  
  7.         © 1998 HAAGE & PARTNER Computer GmbH
  8.  
  9.         written by Jan-Claas Dirks
  10.         basing on code by Thomas Mittelsdorf,
  11.         Commodore-Amiga and Amiga Technologies.
  12.  
  13.         This gadget resembles the old-fashioned station
  14.         dial of a radio.
  15.         Click on it's knob and drag it to the left or right
  16.         to change the value. You can turn around the knob
  17.         several times until you reach the gadgets upper
  18.         or lower limit.
  19.  
  20.         To use this source as a template for your gadget,
  21.         search for comments that begin with "//!".
  22.         This string points you to key information
  23.         you will need to change.
  24.  
  25.         BTW: I use GoldEd's folding feature with modified
  26.         start/end markers: //S/ and //E/. This gives the
  27.         opportunity to do nested folding.
  28. */
  29.  
  30. //S/ Includes
  31. #include  <clib/alib_protos.h>
  32. #include  <clib/macros.h>
  33. #include  <string.h>
  34. #include  <stdlib.h>
  35. #include  <math.h>
  36.  
  37. #include  <exec/exec.h>
  38. #include  <exec/memory.h>
  39. #include  <exec/libraries.h>
  40.  
  41. #include  <pragma/exec_lib.h>
  42. #include  <pragma/intuition_lib.h>
  43.  
  44. #include  <pragma/exec_lib.h>
  45. #include  <pragma/gadtools_lib.h>
  46. #include  <pragma/graphics_lib.h>
  47. #include  <pragma/intuition_lib.h>
  48. #include  <pragma/layers_lib.h>
  49. #include  <pragma/utility_lib.h>
  50.  
  51. #include  <graphics/clip.h>
  52. #include  <graphics/rastport.h>
  53. #include  <graphics/gfxmacros.h>
  54.  
  55. #include  <intuition/gadgetclass.h>
  56. #include  <intuition/intuition.h>
  57. #include  <intuition/imageclass.h>
  58.  
  59. #include  <utility/utility.h>
  60. #include  <libraries/wizard.h>
  61.  
  62. #include  <libraries/wizardextern.h>
  63.  
  64. //! This is the definition of the tags for our gadget
  65. #include  "radiodiallib.h"
  66. //E/
  67.  
  68. //S/ Debug macros
  69. //! Set MYDEBUG to 1 to get debug output.
  70. //  Set bug to the printf-style output function to be called.
  71. //  Use these macros this way: D(bug("x is %ld\n", x));
  72. //  To use kprintf(), include "debug.lib" in your project.
  73. #define MYDEBUG 0
  74. void kprintf(UBYTE *fmt,...);
  75. void dprintf(UBYTE *fmt,...);
  76. #define bug kprintf
  77. #if MYDEBUG
  78. #define D(x) x
  79. #else
  80. #define D(x) ;
  81. #endif /* MYDEBUG */
  82. //E/
  83.  
  84. struct WizardRadioDialBase
  85.   {
  86.   struct Library library;
  87.   ULONG result;
  88.   };
  89.  
  90. //S/ Defines
  91. #pragma libbase WizardRadioDialBase;
  92.  
  93. //! This is the name of the library and it's version string
  94. #define _LibNameString "wizard_radiodial.library"
  95. #define _LibVersionString _LibNameString " 1.0 (" __DATE__ ")"
  96.  
  97. // some casting abbrevations
  98. #define OPSET(x)    ((struct opSet *)x)
  99. #define OPGET(x)    ((struct opGet *)x)
  100. #define GPRENDER(x) ((struct gpRender *)x)
  101. #define GADGET(x)   ((struct Gadget *)x)
  102. #define GDIM(x)     ((struct grmDimensions *)x)
  103. #define GPINPUT(x)  ((struct gpInput *)x)
  104. #define GPINACT(x)  ((struct gpGoInactive *)x)
  105. #define OPUPDATE(x) ((struct opUpdate *)x)
  106. //E/
  107.  
  108. //S/ Variablen
  109. //! This struct holds the attributes of a gadget instance.
  110. //  Remember, one shared library controls all instances of
  111. //  your gadget, thus you must not use global variables to
  112. //  store attributes of one particular gadget.
  113. //  A pointer to an instance of this struct will be passed
  114. //  to you by Intuition whenever needed.
  115.  
  116. typedef struct {
  117.     //! Some attributes for StormWizard
  118.     UWORD MinWidth, MinHeight;          // minimum layout size
  119.     struct Rectangle ClipRectangle;     // for rendering
  120.     BOOL Active;                        // gadget visible or not
  121.     UWORD ShortCutKey;                  // short cut key
  122.  
  123.     long minlimit, maxlimit, value;     // see radiodiallib.h
  124.     WORD rastersteps, rasteroffset;
  125.  
  126.     WORD lastx;                         // last processed ie->ie_X value
  127.     long lastvalue;                     // backed-up value for canceling
  128.     struct
  129.  
  130.     {
  131.         WORD x, y, radius;
  132.     } knob;                             // internal: dial's geometry
  133.  
  134.     struct
  135.     {
  136.         WORD x, y, radius;
  137.     } dial;                             // internal: knob's geometry
  138. } LibData;
  139.  
  140. extern ULONG HookEntry();
  141.  
  142. struct Library  *DOSBase;
  143. struct Library  *MathIeeeDoubBasBase;
  144. struct Library  *MathIeeeDoubTransBase;
  145. struct Library  *GfxBase;
  146. struct Library  *IntuitionBase;
  147. struct Library  *LayersBase;
  148. struct Library  *UtilityBase;
  149. //E/
  150.  
  151. static void SetKnobPosition(LibData *data)
  152. //S/
  153. {
  154.     // given a LibData structure, this functions sets the
  155.     // position of the knob according to its value.
  156.  
  157.     double x, y;
  158.     double cx, cy;
  159.     double a, sinA, cosA;
  160.  
  161.     x = (double)data->dial.x;
  162.     y = (double)(data->dial.y - (data->dial.radius*3)/4);
  163.     cx = (double)data->dial.x;
  164.     cy = (double)data->dial.y;
  165.     a = (double)(2*PI*(data->rasteroffset - data->minlimit + data->value) / data->rastersteps);
  166.     sinA = sin(a);
  167.     cosA = cos(a);
  168.  
  169.     data->knob.x = data->dial.x + (WORD)floor(x*cosA - y*sinA - cx*cosA + cy*sinA + 0.5);
  170.     data->knob.y = data->dial.y + (WORD)floor(x*sinA + y*cosA - cx*sinA - cy*cosA + 0.5);
  171. }
  172. //E/
  173.  
  174. void INIT_9_OpenLibs(void)
  175. //S/
  176. {
  177.     //! I use StromC's INIT_n_-mechanism
  178.     //  for automatic initialisation
  179.     GfxBase = OpenLibrary("graphics.library", 37);
  180.     IntuitionBase = OpenLibrary("intuition.library", 37);
  181.     LayersBase = OpenLibrary("layers.library", 37);
  182.     UtilityBase = OpenLibrary("utility.library", 37);
  183.     MathIeeeDoubBasBase = OpenLibrary("mathieeedoubbas.library", 37);
  184.     MathIeeeDoubTransBase = OpenLibrary("mathieeedoubtrans.library", 37);
  185.  
  186. }
  187. //E/
  188.  
  189. void EXIT_9_CloseLibs(void)
  190. //S/
  191. {
  192.     if (MathIeeeDoubBasBase)
  193.         CloseLibrary(MathIeeeDoubBasBase);
  194.     if (MathIeeeDoubTransBase)
  195.         CloseLibrary(MathIeeeDoubTransBase);
  196.     if (GfxBase)
  197.         CloseLibrary(GfxBase);
  198.     if (IntuitionBase)
  199.         CloseLibrary(IntuitionBase);
  200.     if (LayersBase)
  201.         CloseLibrary(LayersBase);
  202.     if(UtilityBase)
  203.         CloseLibrary(UtilityBase);
  204. }
  205. //E/
  206.  
  207. static ULONG Notify(Object *obj,
  208.                     struct GadgetInfo *gi,
  209.                     ULONG flags,
  210.                     Tag tag1,
  211.                     ...)
  212. //S/
  213. {
  214.     return (DoMethod(obj, OM_NOTIFY, (struct TagItem*)&tag1, gi, flags));
  215. }
  216. //E/
  217.  
  218. static void SendMsg(IClass *class,
  219.                     Object *obj,
  220.                     Msg msg)
  221. //S/
  222. {
  223.     struct TagItem tags[2];
  224.     tags[0].ti_Tag = GA_ID;
  225.     tags[0].ti_Data = GADGET(obj)->GadgetID;
  226.     tags[1].ti_Tag = TAG_DONE;
  227.     DoSuperMethod(class, obj, OM_NOTIFY, tags, GPINPUT(msg)->gpi_GInfo, 0);
  228. }
  229. //E/
  230.  
  231. static ULONG Dispatcher(IClass *class,
  232.                         Object *obj,
  233.                         Msg msg)
  234. //S/
  235. {
  236.     LibData *data;
  237.     ULONG retval = NULL;
  238.     struct TagItem *tag, *tstate;
  239.     struct DrawInfo *drinfo;
  240.     BOOL redraw;
  241.     struct InputEvent*  ie;
  242.     struct Gadget *g = GADGET(obj); // abbrevation: save some casts and null-indices
  243.  
  244.     // OM_NEW has no information about obj yet.
  245.     if (msg->MethodID != OM_NEW)
  246.         data = INST_DATA(class, obj);
  247.  
  248.     switch (msg->MethodID)
  249.     {
  250.         case OM_NEW:
  251. //S/
  252.             // Creation of this gadget
  253.             D(bug("** OM_NEW\n"));
  254.  
  255.             if ((retval = DoSuperMethodA(class, obj, msg)))
  256.             {
  257.                 data = INST_DATA(class, retval);
  258.  
  259.                 //! Initialize default values for a gadget instance.
  260.                 data->MinWidth = 8;
  261.                 data->MinHeight = 8;
  262.  
  263.                 data->minlimit = 0;
  264.                 data->maxlimit = 100;
  265.                 data->value = 0;
  266.                 data->rastersteps = 36;
  267.                 data->rasteroffset = 0;
  268.                 //! Don't worry about any attributes that depend on the layout.
  269.                 //  There will be a WEXTERNM_lAYOUT call later.
  270.  
  271.                 //  read attributes from the tag list.
  272.                 tstate = OPSET(msg)->ops_AttrList;
  273.                 while ((tag = NextTagItem(&tstate))!=NULL)
  274.                 {
  275.                     switch (tag->ti_Tag)
  276.                     {
  277.                         case GA_DrawInfo:
  278.                             drinfo = (struct DrawInfo *)tag->ti_Data;
  279.                             break;
  280.                         case WGA_MinWidth:
  281.                             data->MinWidth = (UWORD)tag->ti_Data;
  282.                             break;
  283.                         case WGA_MinHeight:
  284.                             data->MinHeight = (UWORD)tag->ti_Data;
  285.                             break;
  286.  
  287.                         //! Overriding the default values on gadget creation time.
  288.                         case RADIODIAL_MinLimit:
  289.                             data->minlimit = tag->ti_Data;
  290.                             break;
  291.                         case RADIODIAL_MaxLimit:
  292.                             data->maxlimit = tag->ti_Data;
  293.                             break;
  294.                         case RADIODIAL_Value:
  295.                             data->value = tag->ti_Data;
  296.                             break;
  297.                         case RADIODIAL_RasterSteps:
  298.                             data->rastersteps = tag->ti_Data;
  299.                             break;
  300.                         case RADIODIAL_RasterOffset:
  301.                             data->rasteroffset = tag->ti_Data;
  302.                             break;
  303.                     }
  304.                 }
  305.             }
  306.             break;
  307. //E/
  308.         case OM_SET:
  309.         case OM_UPDATE:
  310. //S/
  311.             // SetGadgetAttrs() and notifying
  312.             D(bug("** OM_SET / OM_UPDAtE\n"));
  313.  
  314.             retval=DoSuperMethodA(class, obj, msg);
  315.  
  316.             //! Now we do our own processing
  317.             redraw = FALSE;
  318.             tstate = OPSET(msg)->ops_AttrList;
  319.             while ((tag = NextTagItem(&tstate))!=NULL)
  320.             {
  321.                 switch (tag->ti_Tag)
  322.                 {
  323.                     case RADIODIAL_MinLimit:
  324.                         data->minlimit = (long)tag->ti_Data;
  325.                         break;
  326.  
  327.                     case RADIODIAL_MaxLimit:
  328.                         data->maxlimit = (long)tag->ti_Data;
  329.                         break;
  330.  
  331.                     case RADIODIAL_Value:
  332.                         if ((long)tag->ti_Data < data->minlimit)
  333.                             data->value = data->minlimit;
  334.                         else
  335.                             if ((long)tag->ti_Data > data->maxlimit)
  336.                                 data->value = data->maxlimit;
  337.                             else
  338.                                 data->value = (long)tag->ti_Data;
  339.  
  340.                         redraw = TRUE;
  341.  
  342.                         SetKnobPosition(data);
  343.                         Notify(obj, OPSET(msg)->ops_GInfo, OPSET(msg)->MethodID == OM_UPDATE ? OPUPDATE(msg)->opu_Flags : 0L, GA_ID, g->GadgetID, RADIODIAL_Value, data->value, TAG_END);
  344.                         break;
  345.                 }
  346.  
  347.                 if (redraw && data->Active)
  348.                 {
  349.                     struct RastPort *rp;
  350.                     if ((rp = ObtainGIRPort(OPSET(msg)->ops_GInfo)) != NULL)
  351.                     {
  352.                         DoMethod(obj, GM_RENDER, OPSET(msg)->ops_GInfo, rp, GREDRAW_REDRAW);
  353.                         ReleaseGIRPort(rp);
  354.                     }
  355.                 }
  356.             }
  357.             break;
  358. //E/
  359.         case OM_GET:
  360. //S/
  361.             // GetAttr()
  362.             D(bug("** OM_GET\n"));
  363.  
  364.             retval = TRUE;
  365.  
  366.             switch (OPGET(msg)->opg_AttrID)
  367.             {
  368.                 //! Someone in the outside world is interested in us
  369.  
  370.                 case WGA_MinWidth:
  371.                     *(OPGET(msg)->opg_Storage) = (ULONG)data->MinWidth;
  372.                     break;
  373.                 case WGA_MinHeight:
  374.                     *(OPGET(msg)->opg_Storage) = (ULONG)data->MinHeight;
  375.                     break;
  376.                 case RADIODIAL_MinLimit:
  377.                     *(OPGET(msg)->opg_Storage) = (ULONG)data->minlimit;
  378.                     break;
  379.                 case RADIODIAL_MaxLimit:
  380.                     *(OPGET(msg)->opg_Storage) = (ULONG)data->maxlimit;
  381.                     break;
  382.                 case RADIODIAL_Value:
  383.                     *(OPGET(msg)->opg_Storage) = (ULONG)data->value;
  384.                     break;
  385.                 case RADIODIAL_RasterSteps:
  386.                     *(OPGET(msg)->opg_Storage) = (ULONG)data->rastersteps;
  387.                     break;
  388.                 case RADIODIAL_RasterOffset:
  389.                     *(OPGET(msg)->opg_Storage) = (ULONG)data->rasteroffset;
  390.                     break;
  391.                 default:
  392.                     retval = DoSuperMethodA(class, obj, msg);
  393.             }
  394.             break;
  395. //E/
  396.         case GM_HITTEST:
  397. //S/
  398.             // SELECT_DOWN
  399.             D(bug("** GM_HITTEST\n"));
  400.  
  401.             //! The mouse clicked over our gadget,
  402.             //  this gadget does not check if it's
  403.             //  particular graphics was hit.
  404.             retval = GMR_GADGETHIT;
  405.             break;
  406. //E/
  407.         case GM_HELPTEST:
  408. //S/
  409.             // HELP test
  410.             D(bug("** GM_HELPTEST\n"));
  411.  
  412.             //! Actually, we don't react on this.
  413.             if (data->Active)
  414.                 retval = DoSuperMethodA(class, obj, msg);
  415.             break;
  416. //E/
  417.         case GM_GOACTIVE:
  418. //S/
  419.             // grab the input focus?
  420.             D(bug("** GM_GOACTIVE\n"));
  421.  
  422.             if (!data->Active)
  423.                 retval = GMR_NOREUSE;
  424.             else
  425.             {
  426.                 ie = GPINPUT(msg)->gpi_IEvent;
  427.                 //! this gadget does not react on ActivateGadget()
  428.                 if (ie)
  429.                 {
  430.                     retval = GMR_MEACTIVE;
  431.                     data->lastx = GADGET(obj)->LeftEdge + GPINPUT(msg)->gpi_Mouse.X;
  432.                     data->lastvalue = data->value;
  433.                 }
  434.             }
  435.             break;
  436. //E/
  437.         case GM_GOINACTIVE:
  438. //S/
  439.             // after the input focus has been released
  440.             D(bug("** GM_GOINACTIVE\n"));
  441.  
  442.             //! You probabilly need to redraw your gadget
  443.             //  in an inactive look. This gadget doesn't.
  444.             retval = DoSuperMethodA(class, obj, msg);
  445.             break;
  446. //E/
  447.         case GM_HANDLEINPUT:
  448. //S/
  449.             // process user input on our gadget
  450.             D(bug("** GM_HANDLEINPUT\n"));
  451.  
  452.             ie = GPINPUT(msg)->gpi_IEvent;
  453.             retval = GMR_MEACTIVE;
  454.  
  455.             //! Now for the interaction:
  456.             if (ie->ie_Class == IECLASS_RAWMOUSE)
  457.             {
  458.                 switch (ie->ie_Code)
  459.                 {
  460.                     case SELECTUP:
  461.                         if (((GPINPUT(msg)->gpi_Mouse).X < 0) ||
  462.                             ((GPINPUT(msg)->gpi_Mouse).X >= g->Width) ||
  463.                             ((GPINPUT(msg)->gpi_Mouse).Y < 0) ||
  464.                             ((GPINPUT(msg)->gpi_Mouse).Y >= g->Height))
  465.                         {
  466.                             D(bug("  UP and VERIFY\n"));
  467.                             retval = GMR_NOREUSE | GMR_VERIFY;
  468.                         }
  469.                         else
  470.                         {
  471.                             D(bug("  UP\n"));
  472.                             retval = GMR_NOREUSE;
  473.                         }
  474.                         break;
  475.  
  476.                     case MENUDOWN:
  477.                         D(bug("  CANCEL\n"));
  478.                         SetGadgetAttrs(g, GPINPUT(msg)->gpi_GInfo->gi_Window, NULL, RADIODIAL_Value, data->lastvalue, TAG_END);
  479.                         SendMsg(class, obj, msg);
  480.                         retval = GMR_REUSE;
  481.                         break;
  482.  
  483.                     default:
  484.                         // overrides a bug: at most times the last message has the mouse at (0/0)
  485.                         if (ie->ie_X != 0 && ie->ie_Y != 0)
  486.                         {
  487.                             D(bug("  %4ld, %4ld, %4ld", data->value,ie->ie_X, data->lastx));
  488.                             SetGadgetAttrs(g, GPINPUT(msg)->gpi_GInfo->gi_Window, NULL, RADIODIAL_Value, data->value + (ie->ie_X - data->lastx) / 2, TAG_END);
  489.                             SendMsg(class, obj, msg);
  490.                             data->lastx = ie->ie_X;
  491.                         }
  492.                         break;
  493.                 }
  494.             }
  495.             break;
  496. //E/
  497.         case GM_RENDER:
  498. //S/
  499.             // RefreshGadgets(), RefreshGList()
  500.             D(bug("** GM_RENDER\n"));
  501.             {
  502.                 struct GadgetInfo *GInfo = GPRENDER(msg)->gpr_GInfo;
  503.                 struct RastPort *rp = GPRENDER(msg)->gpr_RPort;
  504.                 struct Region *OldRegion;
  505.  
  506.                 if (DoSuperMethod(class, obj, WEXTERNM_INSTALLCLIP, GInfo, &OldRegion))
  507.                 {
  508.                     struct DrawInfo *DrInfo = GInfo->gi_DrInfo;
  509.                     //! use exactly this rastPort etc. to draw your gadget right now.
  510.  
  511.                     SetAPen(rp, DrInfo->dri_Pens[BACKGROUNDPEN]);
  512.                     RectFill(rp, g->LeftEdge, g->TopEdge, g->LeftEdge+g->Width-1, g->TopEdge+g->Height-1);
  513.  
  514.                     // Now you get an idea why the visual appearance of this gadget
  515.                     // remembers of good ol' 8-bit times:
  516.                     SetAPen(rp, DrInfo->dri_Pens[TEXTPEN]);
  517.                     DrawCircle(rp, data->dial.x, data->dial.y, data->dial.radius);
  518.                     DrawCircle(rp, data->knob.x, data->knob.y, data->knob.radius);
  519.  
  520.                     DoSuperMethod(class, obj, WEXTERNM_UNINSTALLCLIP, GInfo, OldRegion);
  521.                 }
  522.             }
  523.             break;
  524. //E/
  525.         case WEXTERNM_LAYOUT:
  526. //S/
  527.             // Position / size may have changed
  528.             D(bug("** WEXTERNM_LAYOUT\n"));
  529.  
  530.             // Needed calculations for any external gadget
  531.             data->ClipRectangle = ((struct WizardExternLayout *)msg)->wepl_ClipRectangle;
  532.  
  533.             g->LeftEdge = ((struct WizardExternLayout *)msg)->wepl_Bounds.Left;
  534.             g->TopEdge = ((struct WizardExternLayout *)msg)->wepl_Bounds.Top;
  535.             g->Width = ((struct WizardExternLayout *)msg)->wepl_Bounds.Width;
  536.             g->Height = ((struct WizardExternLayout *)msg)->wepl_Bounds.Height;
  537.  
  538.             //! These are our attributes that need to be re-calculated
  539.             //  if the gadget layout changes.
  540.             data->dial.x = g->LeftEdge + g->Width/2;
  541.             data->dial.y = g->TopEdge + g->Height/2;
  542.             data->dial.radius = MIN(g->Width, g->Height) / 2 - 1;
  543.  
  544.             SetKnobPosition(data);
  545.             data->knob.radius = MAX(3, data->dial.radius / 6);
  546.  
  547.             retval=DoSuperMethodA(class, obj, msg);
  548.             break;
  549. //E/
  550.         case WEXTERNM_UPDATEPAGE:
  551. //S/
  552.             // visibility of this gadget
  553.             D(bug("** WEXTERNM_UPDATEPAGE\n"));
  554.  
  555.             data->Active = ((struct WizardExternUpdatePage *)msg)->wepup_Active;
  556.             retval=DoSuperMethodA(class, obj, msg);
  557.             break;
  558. //E/
  559.         default:
  560. //S/
  561.             retval=DoSuperMethodA(class, obj, msg);
  562.             break;
  563. //E/
  564.     }
  565.  
  566.     return retval;
  567. }
  568. //E/
  569.  
  570. //! Following are the two public functions of this library.
  571. //  If you haven't changed the name of the dispatcher function
  572. //  or the gadget instance struct, you do not need to change
  573. //  anything below this point - besides the debug output.
  574.  
  575. struct IClass *privat_MakeClass(register __a0 struct IClass *parentclass)
  576. //S/
  577. {
  578.     struct IClass *myclass;
  579.  
  580.     if ((myclass = MakeClass(0, 0, parentclass, sizeof(LibData), 0)))
  581.     {
  582.         myclass->cl_Dispatcher.h_Entry = HookEntry;
  583.         myclass->cl_Dispatcher.h_SubEntry = (ULONG(*)())&Dispatcher;
  584.         //!
  585.         D(bug("** wizard_radialdial.library ist there.\n"));
  586.     }
  587.  
  588.     return myclass;
  589. }
  590. //E/
  591.  
  592. void privat_FreeClass(register __a0 struct IClass *myclass)
  593. //S/
  594. {
  595.     FreeClass(myclass);
  596. }
  597. //E/
  598.  
  599.